﻿#region Copyright
// Copyright (c) 2011-2012 RaisingForce Team (Alikin Sergey)
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion

using RaisingForce.Raise.Measures;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Globalization;

namespace RaisingForce.Raise.Tests
{


    /// <summary>
    ///Это класс теста для TimeTest, в котором должны
    ///находиться все модульные тесты TimeTest
    ///</summary>
    [TestClass()]
    public class TimeTest
    {


        private TestContext testContextInstance;

        /// <summary>
        ///Получает или устанавливает контекст теста, в котором предоставляются
        ///сведения о текущем тестовом запуске и обеспечивается его функциональность.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Дополнительные атрибуты теста
        // 
        //При написании тестов можно использовать следующие дополнительные атрибуты:
        //
        //ClassInitialize используется для выполнения кода до запуска первого теста в классе
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //ClassCleanup используется для выполнения кода после завершения работы всех тестов в классе
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //TestInitialize используется для выполнения кода перед запуском каждого теста
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //TestCleanup используется для выполнения кода после завершения каждого теста
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion


        [TestMethod]
        public void SerializationTest()
        {
            // default
            Time actual = new Time();
            Time expected = Time.Unknown;
            SerializationHelper.Test(ref actual);
            Assert.AreEqual(expected, actual);
            // unknown
            actual = Time.Unknown;
            expected = Time.Unknown;
            SerializationHelper.Test(ref actual);
            Assert.AreEqual(expected, actual);
            // 30 seconds
            actual = Time.DefineInSeconds(30);
            expected = Time.DefineInMinutes(0.5);
            SerializationHelper.Test(ref actual);
            Assert.AreEqual(expected, actual);
            // 1.5 minutes
            actual = Time.DefineInMinutes(1.5);
            expected = Time.DefineInSeconds(90);
            SerializationHelper.Test(ref actual);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///Тест для CompareTo
        ///</summary>
        [TestMethod()]
        public void CompareToTest()
        {
            // default.CompareTo(null) == +1
            Time target = new Time();
            object obj = null;
            int expected = +1;
            int actual;
            actual = target.CompareTo(obj);
            Assert.AreEqual(expected, actual);
            // default.CompareTo(string) == +1
            target = new Time();
            obj = "abcd";
            expected = +1;
            actual = target.CompareTo(obj);
            Assert.AreEqual(expected, actual);
            // default.CompareTo(unknown) == 0
            target = new Time();
            obj = Time.Unknown;
            expected = 0;
            actual = target.CompareTo(obj);
            Assert.AreEqual(expected, actual);
            // unknown.CompareTo(5 seconds) == -1
            target = Time.Unknown;
            obj = new Time(5, TimeMeasures.Second);
            expected = -1;
            actual = target.CompareTo(obj);
            Assert.AreEqual(expected, actual);
            // (1 minute).CompareTo(61 seconds) == -1
            target = Time.DefineInMinutes(1);
            obj = Time.DefineInSeconds(61);
            expected = -1;
            actual = target.CompareTo(obj);
            Assert.AreEqual(expected, actual);
            // (0.2 minutes).CompareTo(100 milliseconds) == +1
            target = Time.DefineInMinutes(0.2);
            obj = Time.DefineInMilliseconds(100);
            expected = +1;
            actual = target.CompareTo(obj);
            Assert.AreEqual(expected, actual);
            // (1200 milliseconds).CompareTo(1.2 seconds) == 0
            target = Time.DefineInMilliseconds(1200);
            obj = Time.DefineInSeconds(1.2);
            expected = 0;
            actual = target.CompareTo(obj);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///Тест для DefineInSeconds
        ///</summary>
        [TestMethod()]
        public void DefineInSecondsTest()
        {
            // 5.6 seconds
            double measureValue = 5.6;
            Time expected = new Time(5.6, TimeMeasures.Second);
            Time actual;
            actual = Time.DefineInSeconds(measureValue);
            Assert.AreEqual(expected, actual);
            // 0 seconds == Unknown
            measureValue = 0;
            expected = Time.Unknown;
            actual = Time.DefineInSeconds(measureValue);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///Тест для DefineInMinutes
        ///</summary>
        [TestMethod()]
        public void DefineInMinutesTest()
        {
            double measureValue = 1;
            Time expected = new Time(1, TimeMeasures.Minute);
            Time actual;
            actual = Time.DefineInMinutes(measureValue);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///Тест для DefineInMilliseconds
        ///</summary>
        [TestMethod()]
        public void DefineInMillisecondsTest()
        {
            double measureValue = 0.3;
            Time expected = new Time(0.3, TimeMeasures.Millisecond);
            Time actual;
            actual = Time.DefineInMilliseconds(measureValue);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///Тест для DefineInHours
        ///</summary>
        [TestMethod()]
        public void DefineInHoursTest()
        {
            double measureValue = 0.015;
            Time expected = new Time(0.015, TimeMeasures.Hour);
            Time actual;
            actual = Time.DefineInHours(measureValue);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///Тест для Get
        ///</summary>
        [TestMethod()]
        public void GetTest()
        {
            // 0 seconds == unknown
            Time target = new Time();
            ITimeMeasure measure = TimeMeasures.Second;
            double expected = Time.UnknownValue;
            double actual;
            actual = target.Get(measure);
            Assert.AreEqual(expected, actual);
            // 1.5 seconds == 1500 milliseconds
            target = Time.DefineInSeconds(1.5);
            measure = TimeMeasures.Millisecond;
            expected = 1500;
            actual = target.Get(measure);
            Assert.AreEqual(expected, actual);
            // 600 milliseconds == 0.01 minutes
            target = Time.DefineInMilliseconds(600);
            measure = TimeMeasures.Minute;
            expected = 0.01;
            actual = target.Get(measure);
            Assert.AreEqual(expected, actual);
            // 3 hour == 10800 seconds
            target = Time.DefineInHours(3);
            measure = TimeMeasures.Second;
            expected = 10800;
            actual = target.Get(measure);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///Тест для ToString
        ///</summary>
        [TestMethod()]
        public void ToStringTest()
        {
            // default -> UnknownString
            Time target = new Time();
            string format = null;
            IFormatProvider formatProvider = null;
            string expected = Time.UnknownString;
            string actual;
            actual = target.ToString(format, formatProvider);
            Assert.AreEqual(expected, actual);
            // unknown -> UnknownString
            target = Time.Unknown;
            actual = target.ToString(format, formatProvider);
            Assert.AreEqual(expected, actual);
            // 5 seconds -> 5 сек
            target = Time.DefineInSeconds(5);
            formatProvider = CultureInfo.InvariantCulture;
            expected = "5.0 " + TimeMeasures.Second.ShortName;
            actual = target.ToString(format, formatProvider);
            Assert.AreEqual(expected, actual);
            format = "F0";
            expected = "5 " + TimeMeasures.Second.ShortName;
            actual = target.ToString(format, formatProvider);
            Assert.AreEqual(expected, actual);
            // 90000 milliseconds -> 1.5 мин
            target = Time.DefineInMilliseconds(90000);
            format = "F2";
            formatProvider = CultureInfo.GetCultureInfo("ru-RU");
            expected = "1,50 " + TimeMeasures.Minute.ShortName;
            actual = target.ToString(format, formatProvider);
            Assert.AreEqual(expected, actual);
            // 5400 seconds
            target = Time.DefineInSeconds(5400);
            format = null;
            formatProvider = CultureInfo.InvariantCulture;
            expected = "1.5 " + TimeMeasures.Hour.ShortName;
            actual = target.ToString(format, formatProvider);
            Assert.AreEqual(expected, actual);
            // 0.015 seconds
            target = Time.DefineInSeconds(0.015);
            format = null;
            formatProvider = CultureInfo.InvariantCulture;
            expected = "15.0 " + TimeMeasures.Millisecond.ShortName;
            actual = target.ToString(format, formatProvider);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///Тест для op_Subtraction
        ///</summary>
        [TestMethod()]
        public void op_SubtractionTest()
        {
            // 15min - unknown = unknown - 15min = unknown
            Time first = Time.DefineInMinutes(15);
            Time second = Time.Unknown;
            Time expected = Time.Unknown;
            Time actual;
            actual = (first - second);
            Assert.AreEqual(expected, actual);
            actual = (second - first);
            Assert.AreEqual(expected, actual);
            // 15min - 90000msec = 90000msec - 15min = 13.5min
            first = Time.DefineInMinutes(15);
            second = Time.DefineInMilliseconds(90000);
            expected = Time.DefineInMinutes(13.5);
            actual = (first - second);
            Assert.AreEqual(expected, actual);
            actual = (second - first);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///Тест для ToTimeSpan
        ///</summary>
        [TestMethod()]
        public void ToTimeSpanTest()
        {
            // default
            Time target = new Time();
            TimeSpan expected = new TimeSpan();
            TimeSpan actual;
            actual = target.ToTimeSpan();
            Assert.AreEqual(expected, actual);
            // unknown
            target = Time.Unknown;
            expected = new TimeSpan();
            actual = target.ToTimeSpan();
            Assert.AreEqual(expected, actual);
            // 150 milliseconds
            target = Time.DefineInMilliseconds(150);
            expected = new TimeSpan(0, 0, 0, 0, 150);
            actual = target.ToTimeSpan();
            Assert.AreEqual(expected, actual);
            // 2 seconds
            target = Time.DefineInSeconds(2);
            expected = new TimeSpan(0, 0, 2);
            actual = target.ToTimeSpan();
            Assert.AreEqual(expected, actual);
            // 2 seconds and 15 milliseconds
            target = Time.DefineInSeconds(2)
                + Time.DefineInMilliseconds(15);
            expected = new TimeSpan(0, 0, 0, 2, 15);
            actual = target.ToTimeSpan();
            Assert.AreEqual(expected, actual);
            // 3 minutes
            target = Time.DefineInMinutes(3);
            expected = new TimeSpan(0, 3, 0);
            actual = (TimeSpan)target;          // explicit conversion
            Assert.AreEqual(expected, actual);
            // 3 minutes, 15 seconds and 23 milliseconds
            target = Time.DefineInMinutes(3)
                + Time.DefineInSeconds(15)
                + Time.DefineInMilliseconds(23);
            expected = new TimeSpan(0, 0, 3, 15, 23);
            actual = target.ToTimeSpan();
            Assert.AreEqual(expected, actual);
            // 30 hours
            target = Time.DefineInHours(30);
            expected = new TimeSpan(30, 0, 0);
            actual = target.ToTimeSpan();
            Assert.AreEqual(expected, actual);
            // 30 hours, 21 minutes, 10 seconds and 100 milliseconds
            target = Time.DefineInHours(30)
                + Time.DefineInMinutes(21)
                + Time.DefineInSeconds(10)
                + Time.DefineInMilliseconds(100);
            expected = new TimeSpan(0, 30, 21, 10, 100);
            actual = target.ToTimeSpan();
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///Тест для FromTimeSpan
        ///</summary>
        [TestMethod()]
        public void FromTimeSpanTest()
        {
            // default
            TimeSpan timeSpan = new TimeSpan();
            Time expected = new Time();
            Time actual;
            actual = Time.FromTimeSpan(timeSpan);
            Assert.IsTrue(actual.IsUnknown);
            Assert.AreEqual(expected, actual);
            expected = Time.Unknown;
            actual = Time.FromTimeSpan(timeSpan);
            Assert.IsTrue(actual.IsUnknown);
            Assert.AreEqual(expected, actual);
            // 150 milliseconds
            timeSpan = new TimeSpan(0, 0, 0, 0, 150);
            expected = Time.DefineInMilliseconds(150);
            actual = Time.FromTimeSpan(timeSpan);
            Assert.AreEqual(expected, actual);
            // 2 seconds
            timeSpan = new TimeSpan(0, 0, 2);
            expected = Time.DefineInSeconds(2);
            actual = Time.FromTimeSpan(timeSpan);
            Assert.AreEqual(expected, actual);
            // 2 seconds and 15 milliseconds
            timeSpan = new TimeSpan(0, 0, 0, 2, 15);
            expected = Time.DefineInSeconds(2) + Time.DefineInMilliseconds(15);
            actual = timeSpan;          // implicit conversion
            Assert.AreEqual(expected, actual);
            // 3 minutes
            timeSpan = new TimeSpan(0, 3, 0);
            expected = Time.DefineInMinutes(3);
            actual = (Time)timeSpan;    // explicit conversion
            Assert.AreEqual(expected, actual);
            // 3 minutes, 15 seconds and 23 milliseconds
            timeSpan = new TimeSpan(0, 0, 3, 15, 23);
            expected = Time.DefineInMinutes(3)
                + Time.DefineInSeconds(15)
                + Time.DefineInMilliseconds(23);
            actual = Time.FromTimeSpan(timeSpan);
            Assert.AreEqual(expected, actual);
            // 30 hours
            timeSpan = new TimeSpan(30, 0, 0);
            expected = Time.DefineInHours(30);
            actual = Time.FromTimeSpan(timeSpan);
            Assert.AreEqual(expected, actual);
            // 30 hours, 21 minutes, 10 seconds and 100 milliseconds
            timeSpan = new TimeSpan(0, 30, 21, 10, 100);
            expected = Time.DefineInHours(30)
                + Time.DefineInMinutes(21)
                + Time.DefineInSeconds(10)
                + Time.DefineInMilliseconds(100);
            actual = Time.FromTimeSpan(timeSpan);
            Assert.AreEqual(expected, actual);
        }
    }
}
